package com.neusoft.databus.policy.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.neusoft.bizcore.web.dto.result.PageResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultDTO;
import com.neusoft.bizcore.web.dto.result.ResultListDTO;
import com.neusoft.bizcore.web.exception.CustomRuntimeException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.databus.common.constant.DatabusErrorCode;
import com.neusoft.databus.policy.converter.PolicyConverter;
import com.neusoft.databus.policy.dto.PolicyDTO;
import com.neusoft.databus.policy.dto.PolicyRefLinkageDTO;
import com.neusoft.databus.policy.enums.EventStatus;
import com.neusoft.databus.policy.model.Event;
import com.neusoft.databus.policy.model.Policy;
import com.neusoft.databus.policy.model.PolicyRefResource;
import com.neusoft.databus.policy.repository.EventRepository;
import com.neusoft.databus.policy.repository.PolicyRepository;
import com.neusoft.databus.policy.service.PolicyService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * 策略管理控制器
 *
 * @author naxiang
 */
@Api("策略管理控制器")
@RestController
@RequestMapping(value = "/api/w/policys")
public class PolicyController {
    @Autowired
    private PolicyRepository policyRepository;
    @Autowired
    private PolicyConverter policyConverter;
    @Autowired
    private PolicyService policyService;
    @Autowired
    private EventRepository eventRepository;

    @ApiOperation("查询所有策略")
    @GetMapping
    public ResultListDTO<PolicyDTO> index(final Searchable searchable) {
        final List<Policy> policies = this.policyRepository.search(searchable);
        final ResultListDTO<PolicyDTO> result = ResultListDTO.success(this.policyConverter.toListDTO(policies));
        return result;
    }

    @ApiOperation("分页查询所有策略")
    @GetMapping("/p")
    public PageResultDTO<PolicyDTO> search(final Searchable searchable, final Pageable pageable) {
        final Page<Policy> models = this.policyRepository.search(pageable, searchable);
        return PageResultDTO.success(this.policyConverter.toPageDTO(models));
    }

    /**
     * 创建策略
     *
     * @param dto
     * @return
     */
    @ApiOperation("创建策略")
    @PostMapping
    public ResultDTO<PolicyDTO> create(@RequestBody final PolicyDTO dto) {
        Policy model = this.policyConverter.toModel(dto);
        model = this.policyService.create(model);
        final PolicyDTO result = this.policyConverter.toDTO(model);
        return ResultDTO.success(result);
    }

    /**
     * 删除策略，物理删除 <br>
     * DELETE <br>
     *
     * @param code 策略编码
     * @return ResultDTO<Void>
     * @throws CustomRuntimeException
     */
    @ApiOperation("删除策略，物理删除")
    @DeleteMapping("/{code}")
    public ResultDTO<Void> delete(@PathVariable final String code) {
        final Policy model = this.policyRepository.findByCode(code);
        if (null == model) {
            throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_404001, new Object[] {code });
        }
        final List<Event> events = this.eventRepository.findByPolicyIdAndStatus(model.getId(), EventStatus.UNFIXED);
        if (events.size() > 0) {
            throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_400002, new Object[] {"该策略存在未解除的告警事件" });
        }
        this.policyService.delete(model);
        return ResultDTO.success();
    }

    /**
     * 更新策略，仅更新资源的基本属性
     *
     * @param code 策略编码
     * @param dto 策略DTO
     * @return ResultDTO<ResourceDTO>
     * @throws CustomRuntimeException
     */
    @ApiOperation(value = "更新策略", notes = "仅更新策略的基本属性")
    @PutMapping("/{code}")
    public ResultDTO<PolicyDTO> update(@PathVariable final String code, @RequestBody final PolicyDTO dto) {
        Policy model = this.policyRepository.findByCode(code);
        if (null == model) {
            throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_404001, new Object[] {code });
        }
        final List<PolicyRefResource> policyRefResources = model.getPolicyRefResources();
        // 强制忽略传递的ID
        dto.setId(model.getId());
        dto.setCode(model.getCode());
        model = this.policyConverter.toModel(dto);
        model.setPolicyRefResources(policyRefResources);
        this.policyService.update(model);
        final PolicyDTO result = this.policyConverter.toDTO(model);
        return ResultDTO.success(result);
    }

    /**
     * 启用策略
     *
     * @param code 资源编码
     * @return ResultDTO<Void>
     * @throws CustomRuntimeException
     */
    @ApiOperation("启用策略")
    @PutMapping("/{code}/enable")
    public ResultDTO<Void> enable(@PathVariable final String code) {
        final Policy model = this.policyRepository.findByCode(code);
        if (null == model) {
            throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_404001, new Object[] {code });
        }
        this.policyService.enable(model);
        return ResultDTO.success();
    }

    /**
     * 禁用策略
     *
     * @param code 策略编码
     * @return ResultDTO<Void>
     * @throws CustomRuntimeException
     */
    @ApiOperation("禁用策略")
    @PutMapping("/{code}/disable")
    public ResultDTO<Void> disable(@PathVariable final String code) {
        final Policy model = this.policyRepository.findByCode(code);
        if (null == model) {
            throw new CustomRuntimeException(DatabusErrorCode.ERR_CODE_404001, new Object[] {code });
        }
        this.policyService.disable(model);
        return ResultDTO.success();
    }

    /**
     * 策略绑定表达式
     *
     * @param id 策略id
     * @param expressionIdList 表达式id
     * @return
     */
    @ApiOperation("策略绑定表达式")
    @PutMapping("/{id}/bindExpression")
    public ResultDTO<PolicyDTO> bindExpression(@PathVariable final Long id,
            @RequestBody final List<Long> expressionIdList) {
        final Policy model = this.policyService.bind(id, expressionIdList);
        final PolicyDTO result = this.policyConverter.toDTO(model);
        return ResultDTO.success(result);
    }

    /**
     * 批量启用策略
     *
     * @param codes策略编码
     * @return
     * @throws CustomRuntimeException
     */
    @ApiOperation("批量启用策略")
    @PutMapping("/enable")
    public ResultDTO<Void> batchEnable(@RequestBody final List<String> codes) {
        final Searchable searchable = new Searchable();
        final String[] policyCodes = {};
        searchable.put("code", codes.toArray(policyCodes));
        searchable.put("disabled", true);
        final List<Policy> policies = this.policyRepository.search(searchable);
        policies.forEach(policy -> {
            this.policyService.enable(policy);
        });
        return ResultDTO.success();
    }

    /**
     * 批量禁用策略
     *
     * @param code 策略编码
     * @return ResultDTO<Void>
     * @throws CustomRuntimeException
     */
    @ApiOperation("批量禁用策略")
    @PutMapping("/disable")
    public ResultDTO<Void> batchDisable(@RequestBody final List<String> codes) {
        final Searchable searchable = new Searchable();
        final String[] policyCodes = {};
        searchable.put("code", codes.toArray(policyCodes));
        searchable.put("disabled", false);
        final List<Policy> policies = this.policyRepository.search(searchable);
        policies.forEach(policy -> {
            this.policyService.disable(policy);
        });
        return ResultDTO.success();
    }

    /**
     * 策略绑定资源
     *
     * @param code
     * @param resourceCodeList
     * @return
     */
    @ApiOperation("策略绑定资源")
    @PutMapping("/{code}/bindResource")
    public ResultDTO<PolicyDTO> bindByCode(@PathVariable final String code,
            @RequestBody final List<String> resourceCodeList) {
        final Policy model = this.policyService.bind(code, resourceCodeList);
        final PolicyDTO result = this.policyConverter.toDTO(model);
        return ResultDTO.success(result);
    }

    /**
     * 策略绑定联动资源
     *
     * @param code
     * @param resourceCodeList
     * @return
     */
    @ApiOperation("策略绑定联动资源")
    @PutMapping("/{code}/bindLinkage")
    public ResultDTO<PolicyDTO> bindLinkageByCode(@PathVariable final String code,
            @RequestBody final List<PolicyRefLinkageDTO> policyRefLinkageDTOs) {
        final Policy model = this.policyService.bindLinkage(code, policyRefLinkageDTOs);
        final PolicyDTO result = this.policyConverter.toDTO(model);
        return ResultDTO.success(result);
    }

}
